/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_test.h"
#include "utils/log.h"
#include <sstream>
#include <iomanip>
#include "CryptoArchitectureKit/crypto_common.h"
#include "CryptoArchitectureKit/crypto_digest.h"

namespace ImageKnifeTest {
using namespace ImageKnifePro;

static bool g_enableCustomKeyGenerator = false;

/**
 * 使用自定义缓存key生成策略示例
 */
class MyKeyGenerator : public CacheKeyGenerator {
public:
    std::string GenerateFileKey(const ImageSource *imageSrc, const std::string &signature = "") override
    {
        g_enableCustomKeyGenerator = true;
        IMAGE_KNIFE_CHECK_RETURN(imageSrc == nullptr, "");
        std::ostringstream src;
        std::string fileName;
        std::string fileKey;
    
        imageSrc->GetString(fileKey);
        src << "loadSrc==" << fileKey << ";";
    
        if (!signature.empty()) {
            src << "signature=" << signature << ";";
        }
    
        DoSha256(src.str(), fileName);
        return fileName;
    }

    std::string GenerateMemoryKey(MemoryKeyParams &memoryKeyParams) override
    {
        g_enableCustomKeyGenerator = true;
        IMAGE_KNIFE_CHECK_RETURN(memoryKeyParams.imageSource == nullptr, "");
        std::string memoryKey;
        Resource resource;
        // 拼接 loadSrc 类型
        std::ostringstream key;
        key << (memoryKeyParams.isAnimator ? "Animator=" : "loadSrc=");
        if (memoryKeyParams.imageSource->GetString(memoryKey)) {
            key << memoryKey << ";";
        } else {
            memoryKeyParams.imageSource->GetResource(resource);
            key << resource.bundleName << "/"
                << resource.moduleName << "/" << memoryKeyParams.colorMode << "/"
                << resource.id << "/" << resource.param << ";";
        }
    
        if (memoryKeyParams.type == ImageKnifePro::ImageRequestType::MAIN_SRC) {
            key << "o:" << static_cast<int>(memoryKeyParams.orientation) << ";";
            if (!memoryKeyParams.transformationInfo.empty()) {
                key << memoryKeyParams.transformationInfo << ";";
            }
    
            if (!memoryKeyParams.downSamplingInfo.empty()) {
                key << memoryKeyParams.downSamplingInfo << ";";
            }
    
            if (!memoryKeyParams.signature.empty()) {
                key << "signature=" << memoryKeyParams.signature << ";";
            }
        }
        return key.str();
    }
private:
    OH_Crypto_ErrCode DoSha256(const std::string &url, std::string &fileName)
    {
        OH_Crypto_ErrCode ret;
        OH_CryptoDigest *ctx = nullptr;
        Crypto_DataBlob in = {.data = (uint8_t *)(url.c_str()), .len = strlen(url.c_str())};
        Crypto_DataBlob out = {.data = nullptr, .len = 0};
        int mdLen = 0;
        ret = OH_CryptoDigest_Create("SHA256", &ctx);
        if (ret != CRYPTO_SUCCESS) {
            return ret;
        }
    
        do {
            ret = OH_CryptoDigest_Update(ctx, &in);
            if (ret != CRYPTO_SUCCESS) {
                break;
            }
            ret = OH_CryptoDigest_Final(ctx, &out);
            if (ret != CRYPTO_SUCCESS) {
                break;
            }
            mdLen = OH_CryptoDigest_GetLength(ctx);
        } while (0);
        const size_t defaultW = 2;
        for (int i = 0; i < out.len; ++i) {
            std::ostringstream oss;
            oss << std::setw(defaultW) << std::setfill('0') << std::hex << static_cast<int>(out.data[i]);
            fileName += oss.str();
        }
        OH_Crypto_FreeDataBlob(&out);
        OH_DigestCrypto_Destroy(ctx);
        return ret;
    }
};

/**
 * 注册自定义缓存key生成策略对象
 * 可以不必导出ArkTs接口，C侧注册一次即可，这里是为了XTS测试导出
 */
static napi_value RegisterCustomKeyGenerator(napi_env env, napi_callback_info info)
{
    ImageKnifePro::ImageKnife::GetInstance().SetCacheKeyGenerator(new MyKeyGenerator());
    return nullptr;
}


static napi_value IsCustomKeyGeneratorEnable(napi_env env, napi_callback_info info)
{
    napi_value value;
    napi_create_int32(env, g_enableCustomKeyGenerator, &value);
    return value;
}

napi_value CustomKeyGeneratorTests(napi_env env, napi_value &exports)
{
    napi_property_descriptor desc[] = {
        {"registerCustomKeyGenerator", nullptr, RegisterCustomKeyGenerator,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"isCustomKeyGeneratorEnable", nullptr, IsCustomKeyGeneratorEnable,
            nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}

}

